package com.sbtr.controller.feature;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sbtr.business.feature.dto.*;
import com.sbtr.business.feature.entity.FeDatafile;
import com.sbtr.business.feature.entity.FeOperator;
import com.sbtr.business.feature.service.FeDatafileService;
import com.sbtr.business.feature.service.FeOperatorService;
import com.sbtr.business.feature.service.impl.FePcaRuleServiceImpl;
import com.sbtr.business.material.service.IMaterialInfoService;
import com.sbtr.business.trainingserver.service.impl.TrainingServerServiceImpl;
import com.sbtr.business.utils.OperatorUtil;
import com.sbtr.common.LoginConstants;
import com.sbtr.common.PageDto;
import com.sbtr.common.PageParams;
import com.sbtr.common.Response;
import com.sbtr.common.calculate.CalculateReflectUtil;
import com.sbtr.common.calculate.DataAnalysisUtil;
import com.sbtr.common.calculate.DataExplorationUtils;
import com.sbtr.common.file.CommonAnalyzeService;
import com.sbtr.common.file.FileService;
import com.sbtr.common.file.dto.FileContentDto;
import com.sbtr.common.file.dto.FileDto;
import com.sbtr.common.file.utils.AbstractNoModelDataListener;
import com.sbtr.controller.common.CommonController;
import com.sbtr.exception.BDException;
import com.sbtr.open.material.dto.MaterialInfoDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 特征算子字段列表 前端控制器
 *
 * @author dgl
 * @since 2023-03-27
 */
@RestController
@RequestMapping("/feOperator")
@Api(tags = "特征算子字段列表")
public class FeOperatorController extends CommonController<FeOperator, FeOperatorService> {

    @Autowired
    OperatorUtil operatorUtil;

    @Autowired
    private IMaterialInfoService materialInfoService;// 素材中数据的具体信息的
    @Autowired
    CommonAnalyzeService commonAnalyzeService;
    @Autowired
    private FileService fileService;

    @Value("${oss.config.uploadPath}")
    private String uploadPath;

    @Autowired
    FeDatafileService feDatafileService;
    @Autowired
    CalculateReflectUtil calculateReflectUtil;//字典对应函数工具

    @GetMapping("/pageList")
    @ApiOperation(httpMethod = "GET", value = "分页列表")
    public Response<PageDto<FeOperator>> pageList(FeOperatorDto feOperatorDto) {
        return Response.success(u.pageList(feOperatorDto));
    }

    @PostMapping("/deleteByIds")
    @ApiOperation(httpMethod = "POST", value = "通用接口---根据id批量删除,逗号分隔ps:'1,2,3'，关联子表删除请重写")
    public Response<String> deleteByIds(String ids) {
        List<String> list = Arrays.asList(ids.split(","));
        QueryWrapper<FeOperator> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("pid", list);
        List<FeOperator> data = u.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(data)) {
            throw new BDException("存在下级，删除失败");
        }
        if (!u.removeByIds(list)) {
            throw new BDException("删除失败");
        }
        return Response.success("删除成功");
    }

    @PostMapping("/save")
    @ApiOperation(httpMethod = "POST", value = "保存")
    public Response<FeOperator> save(@RequestBody FeOperator feOperator) {
        feOperator.setId(null);
        if (feOperator.insert()) {
            return Response.success(feOperator);
        } else throw new BDException("保存失败");
    }


    @GetMapping("/getTree")
    @ApiOperation(httpMethod = "GET", value = "算子树结构")
    public Response<List<FeOperatorTreeDto>> getTree(@RequestParam(value = "canvasId") Long canvasId) {
        return Response.success(u.getTree(canvasId));
    }

    @PostMapping("/exec")
    @ApiOperation(httpMethod = "POST", value = "执行算子")
    public Response<List<LinkedHashMap<String, String>>> exec(@RequestBody FeOperatorExecDto feOperatorExecDto) {
        return Response.success(u.exec(feOperatorExecDto));
    }

    @PostMapping("/execExplore")
    @ApiOperation(httpMethod = "POST", value = "执行数据探索算子")
    public Response<Object> execExplore(@RequestBody FeOperatorExecExploreDto feOperatorExecExploreDto) throws InvocationTargetException, IllegalAccessException {
        Object o = u.execExplore(feOperatorExecExploreDto);
        return Response.success(o);
    }


    @PostMapping("clears")
    @ApiOperation(httpMethod = "POST", value = "根据id批量清除缓存,逗号分隔ps:'1,2,3'")
    public Response<String> clears(String ids) {
        String[] id = ids.split(",");
        operatorUtil.clears(Arrays.asList(id));
        return Response.success("清除成功");
    }

    @GetMapping("getCacheById")
    @ApiOperation(httpMethod = "GET", value = "根据id获取算子的结果，执行过才有，每天凌晨12点清除")
    public Response<PageDto<LinkedHashMap<String, String>>> getCacheById(String id, PageParams pageParams) {
        List<LinkedHashMap<String, String>> list = operatorUtil.getData(id);
        if (list != null) {
            PageDto<LinkedHashMap<String, String>> pageDto = new PageDto<>();
            pageDto.setPage(pageParams.getPage());
            pageDto.setPageSize(pageParams.getPageSize());
            pageDto.setRowCount(list.size());
            int start = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize()));
            int end = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize() + pageParams.getPageSize()));
            pageDto.setList(list.subList(start, Math.min(end, list.size())));
            return Response.success(pageDto);
//           return Response.success(list.subList(0,Math.min(200,list.size())));
        }
        return Response.success(null);
    }

    @GetMapping("getCacheByIds")
    @ApiOperation(httpMethod = "GET", value = "根据id获取算子的结果，执行过才有，每天凌晨12点清除")
    public Response<List<PageDto<LinkedHashMap<String, String>>>> getCacheByIds(String id, PageParams pageParams) {
        List<PageDto<LinkedHashMap<String, String>>> pageDtoList = new ArrayList<>();

        List<LinkedHashMap<String, String>> list = operatorUtil.getData(id);
        if (list != null) {
            PageDto<LinkedHashMap<String, String>> pageDto = new PageDto<>();
            pageDto.setPage(pageParams.getPage());
            pageDto.setPageSize(pageParams.getPageSize());
            pageDto.setRowCount(list.size());
            int start = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize()));
            int end = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize() + pageParams.getPageSize()));
            pageDto.setList(list.subList(start, Math.min(end, list.size())));
            pageDtoList.add(pageDto);
//           return Response.success(list.subList(0,Math.min(200,list.size())));
        }

        if (u.getById(id).getPid() == null) {
            pageDtoList.add(new PageDto<>());
            return Response.success(pageDtoList);
        }

        List<LinkedHashMap<String, String>> list2 = operatorUtil.getData(u.getById(id).getPid().toString());
        if (list2 != null) {
            PageDto<LinkedHashMap<String, String>> pageDto = new PageDto<>();
            pageDto.setPage(pageParams.getPage());
            pageDto.setPageSize(pageParams.getPageSize());
            pageDto.setRowCount(list2.size());
            int start = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize()));
            int end = Integer.parseInt(String.valueOf((pageParams.getPage() - 1) * pageParams.getPageSize() + pageParams.getPageSize()));
            pageDto.setList(list2.subList(start, Math.min(end, list2.size())));
            pageDtoList.add(pageDto);
//           return Response.success(list.subList(0,Math.min(200,list.size())));
        }
        return Response.success(pageDtoList);
    }


    @GetMapping("getCacheTitleById")
    @ApiOperation(httpMethod = "GET", value = "根据id获取算子的标题，执行过才有，每天凌晨12点清除")
    public Response<Map<Long, String>> getTitle(String id) {
        return Response.success(operatorUtil.getTitle(id));
    }

    @PostMapping("exportCacheData")
    @ApiOperation(httpMethod = "POST", value = "选择列导出算子的结果")
    public void exportCacheData(@RequestBody FeOperatorExportDto feOperatorExportDto, HttpServletResponse response, HttpServletRequest request) throws IOException {

        FeOperator feOperator = u.getById(feOperatorExportDto.getId());
        String algorithmUserId = request.getHeader("algorithmUserId");

        List<LinkedHashMap<String, String>> list = operatorUtil.getSelectData(feOperator.getPid().toString(), feOperatorExportDto.getTitles());

        if (feOperatorExportDto.getOutMaterial()!=null&&feOperatorExportDto.getOutMaterial() == 1) {
//            String last = feOperatorExportDto.getExportType() == 2?"xlsx":"txt";
            String bucketDir = uploadPath + "/outMaterial";

            String fileName = feOperatorExportDto.getName();
            String otherName = UUID.randomUUID().toString().replaceAll("-", "") + ".xlsx";

            File pathFile = new File(bucketDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }

            OutputStream os = new FileOutputStream(bucketDir + "/" + otherName);
            EasyExcel.write(os).head(operatorUtil.changeExportHead(feOperatorExportDto.getTitles())).sheet(fileName).doWrite(operatorUtil.getArrayData(list, false, feOperatorExportDto.getTitles()));

            MaterialInfoDto dto = new MaterialInfoDto();
            dto.setBucketDir(bucketDir);

            dto.setFileName(fileName);
            dto.setFileName2(otherName);
            dto.setFileDesc("根据“" + feOperatorExportDto.getName() + "”文件处理后数据所生成的数据集");
            dto.setFileType(feOperatorExportDto.getFileType());
            dto.setCreateTime(new Date());
            dto.setBelonger(algorithmUserId);
            materialInfoService.save(dto);
        }

        if (CollectionUtil.isEmpty(list)) {
            throw new BDException("不存在算子数据");
        }
        String fileName= URLEncoder.encode(feOperatorExportDto.getName(), "utf-8");
        if (feOperatorExportDto.getExportType() == 2) {
//            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            response.setContentType("application/octet-stream");

            response.setHeader("Content-Disposition", "attachment;filename="  + fileName+".xlsx");
            EasyExcel.write(response.getOutputStream()).head(operatorUtil.changeExportHead(feOperatorExportDto.getTitles())).sheet("结果").doWrite(operatorUtil.getArrayData(list, false, feOperatorExportDto.getTitles()));
        } else {
            response.setContentType("application/octet-stream");
//            response.setContentType("text/plain;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" +fileName + ".txt");

            List<List<String>> data = operatorUtil.getArrayData(list, true, feOperatorExportDto.getTitles());
            StringBuilder sb = new StringBuilder();
            for (List<String> params : data) {
                for (String param : params) {
                    sb.append(param).append(" ");
                }
                sb.append("\r\n");
            }
            PrintWriter printWriter = null;
            try {
                printWriter = response.getWriter();
                printWriter.write(sb.toString());
                printWriter.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (printWriter != null) {
                    printWriter.close();
                }
            }
        }
//        return Response.success("导出成功");
    }

    @RequestMapping("/test")
    @ApiOperation(httpMethod = "POST", value = "test")
    public void test(@RequestPart(value = "file") MultipartFile file, HttpServletRequest request) throws IOException {
        FileContentDto fileContentDto = new FileContentDto();
        AbstractNoModelDataListener abstractNoModelDataListener = new AbstractNoModelDataListener(commonAnalyzeService, new HashMap<>());
        EasyExcel.read(file.getInputStream(), abstractNoModelDataListener).sheet().doRead();
        fileContentDto.setContent(abstractNoModelDataListener.resultDataList);
        fileContentDto.setTitle(abstractNoModelDataListener.titleList);

        List<List<String>> list = fileContentDto.getListList();
        //TODO 格式转换都在FileContentDto 里

        System.out.println(JSONUtil.toJsonStr(list));
        System.out.println(JSONUtil.toJsonStr(fileContentDto.getListStr()));
    }


//
//    public List<List<String>> getpcaData(){
//        List<List<String>> list = new ArrayList<>();
//        List<Integer> innerList1 = new ArrayList<>();
//        innerList1.add(1);
//        innerList1.add(2);
//        innerList1.add(3);
//        List<String> stringList1 = new ArrayList<>();
//        for (Integer num : innerList1) {
//            stringList1.add(num.toString());
//        }
//        list.add(stringList1);
//
//        List<Integer> innerList2 = new ArrayList<>();
//        innerList2.add(4);
//        innerList2.add(5);
//        innerList2.add(6);
//        List<String> stringList2 = new ArrayList<>();
//        for (Integer num : innerList2) {
//            stringList2.add(num.toString());
//        }
//        list.add(stringList2);
//
//        List<Integer> innerList3 = new ArrayList<>();
//        innerList3.add(7);
//        innerList3.add(8);
//        innerList3.add(9);
//        List<String> stringList3 = new ArrayList<>();
//        for (Integer num : innerList3) {
//            stringList3.add(num.toString());
//        }
//        list.add(stringList3);
//
//        List<Integer> innerList4 = new ArrayList<>();
//        innerList4.add(10);
//        innerList4.add(11);
//        innerList4.add(12);
//        List<String> stringList4 = new ArrayList<>();
//        for (Integer num : innerList4) {
//            stringList4.add(num.toString());
//        }
//        list.add(stringList4);
//        return list;
//    }

  /*  @PostMapping("/testPca")
    @ApiOperation(httpMethod = "POST", value = "测试PCA算法")
    public void testPca(){
        // 向此训练服务器发送停止任务,调用算法训练端ip/pca接口
        String url = "http://localhost:30004/pca";
        HttpHeaders headers = initRestTemplateHeader();
        String cum_var = "0.95";
        List<List<String>> list = getpcaData();
        // 请求体
        Map<String, Object> postParameters = new HashMap<>();
        postParameters.put("dataArr", list);
        postParameters.put("cum_var", cum_var);
        String jsonBody = JSON.toJSONString(postParameters);
        HttpEntity<String> r = new HttpEntity<>(jsonBody, headers);
        ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, r, String.class);

        // 返回结果
        String body = postForEntity.getBody();
        JSONObject jsObj = JSONObject.parseObject(body);
        if (jsObj.getInteger("ret") != null && 0 == jsObj.getInteger("ret")) {
            System.err.println("--------true-----------");
            System.err.println(jsObj);
            FePcaRuleResultDto fePcaRuleResultDto = JSONUtil.toBean(jsObj.toJSONString(), FePcaRuleResultDto.class);
            //整合数据集
            for (int i = 0; i < 3; i++) {
               System.err.println(JSONUtil.toJsonStr(fePcaRuleResultDto.getX_pca().get(i)));
            }
        } else {
            System.err.println("--------false-----------");
            Integer ret = jsObj.getInteger("ret") != null ? jsObj.getInteger("ret") : 0;
            String msg = StringUtils.isNotBlank(jsObj.getString("msg")) ? jsObj.getString("msg") : "";
        }
    }

    public static HttpHeaders initRestTemplateHeader() {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);// 请求类型
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());// 接收类型
        return headers;
    }*/
}

